Daten dynamisch verwalten
Daten werden in der Regel in Tabellen abgelegt. Bei komplexen Datenstrukturen oder auch bei Daten, die nicht allzulange vorgehalten werden müssen, bietet sich ein EXPORT TO DATABASE an. Zusammen mit der Umwandlung von Daten ins XML-Format kann man eine Menge interessanter Dinge machen. In diesem Beispiel Speichern wir eine Tabelle mit einer bestimmten Struktur und lesen die Daten danach wieder in eine Tabelle mit einer anderen Struktur.
Um was geht es?
Wir simulieren in diesem Beispiel eine Strukturänderung, die in Folge einer Programmerweiterung auftreten kann.
Stellen Sie sich vor, Sie haben eine Struktur in der Sie die Materialnummer und eine Serialnummer zu einem “Vorgang” speichern.
Die Struktur sähe dann z.B. so aus:
TYPES: BEGIN OF ty_struc, vorgang TYPE c LENGTH 10, matnr TYPE c LENGTH 18, sernr TYPE c LENGTH 18, END OF ty_struc.
Die Speicherung erfolgt durch EXPORT TO DATABASE:
EXPORT gt_data TO DATABASE indx(zz) ID ‘$mydata$’.
Das Programm läuft und funktioniert gut. Es werden zu einem Vorgang Materialnummer und Serialnummer gespeichert und gelesen.
Strukturänderung
Nach einiger Zeit erweist es sich jedoch als hilfreich, die Equipmentnummer zum Vorgang ebenfalls zu speichern. Sie fügen den Feldern VORGANG, MATNR und SERNR also das Feld EQUNR hinzu:
TYPES: BEGIN OF ty_struc, vorgang TYPE c LENGTH 10, equnr TYPE c LENGTH 18, matnr TYPE c LENGTH 18, sernr TYPE c LENGTH 18, END OF ty_struc.
Wenn Sie nun allerdings einen alten Vorgang bearbeiten, werden Sie einen Shortdump bekommen:
Laufzeitfehler CONNE_IMPORT_WRONG_COMP_LENG
Ausnahme CX_SY_IMPORT_MISMATCH_ERROR
Die Zusätze IGNORING STRUCTURE BOUNDARIES oder IGNORING CONVERSION CONVERSION ERRORS helfen uns leider nicht weiter.
Die Lösung
Man kann einfach Abhilfe schaffen, in dem man von Anfang an die Daten in ein XML-Objekt umwandelt. Das geht mithilfe von CALL TRANSFORMATION extrem schnell, unkompliziert und sicher.
CALL TRANSFORMATION id SOURCE data = gt_data RESULT XML xml_string.
Der Trick dabei ist, dass im Datencluster nicht vorhandene Felder einfach ignoriert werden. Ebenso werden Felder ignoriert, die zwar im Datencluster, aber nicht in der zu importierenden Struktur/ Tabelle vorhanden sind.
Die Struktur kann fast beliebig geändert werden, solange die Feldnamen identisch bleiben. Sogar Feldtypen können problemlos geändert werden.
Wenn natürlich ein CHAR-Feld in ein INT-Feld geändert wird, dann kann ein C-Wert natürlich nicht in ein numerisches Feld gewandelt werden.
Und wozu brauche ich das?
Die Anwendung ist sicherlich nicht ganz alltäglich, denn normalerweise wird man wohl eine Datenbank-Tabelle definieren und die Daten dort strukturiert ablegen.
Interessant wird es, wenn die Daten zu einer Anwendung teilweise dynamisch – zum Beispiel unterschiedliche Felder je Belegart – verwaltet werden. Sie könnten dann per Customizing zusätzliche Felder definieren, die in einer Anwendung geändert werden sollen. Mittels RTTI ist es inzwischen einfach, anhand eines Feldkatalogs eine interne Tabelle zu generieren.
siehe: Interne Tabelle zur Laufzeit generieren
Zur Anzeige oder Änderung kann dann ein ALV-Grid verwendet werden. Wenn Sie diese Art der Datenspeicherung verwenden, dann kann die Tabellenstruktur fast beliebig geändert werden.
Coding
Das folgende Programm demonstriert das Vorgehen und simuliert die zeitliche Änderung einer Struktur dadurch, das einfach zwei verschiedene Strukturen verwendet werden.
*== old structure TYPES: BEGIN OF ty_test1, eins TYPE c LENGTH 2, zwei TYPE c LENGTH 2, drei TYPE c LENGTH 2, END OF ty_test1. *== new structure TYPES: BEGIN OF ty_test2, neu TYPE c LENGTH 2, eins TYPE c LENGTH 5, zwei TYPE i, END OF ty_test2. *== data tables DATA gt_test1 TYPE STANDARD TABLE OF ty_test1. DATA gt_test2 TYPE STANDARD TABLE OF ty_test2. *== id for storing data DATA gc_id TYPE c LENGTH 20 VALUE '$TRICKTRESOR!'. *== XML-String containing the data in XML-format DATA gv_xml TYPE string. *== exception reference CALL TRANSFORMATION DATA gx_error TYPE REF TO cx_dynamic_check. START-OF-SELECTION. *== add test data to "old" table APPEND 'AA1111' TO gt_test1. APPEND 'BB2222' TO gt_test1. APPEND 'CC3333' TO gt_test1.
*== save xml string into data cluster*== Transform data table into xml string CALL TRANSFORMATION id SOURCE test = gt_test1 RESULT XML gv_xml. EXPORT test = gv_xml TO DATABASE indx(zv) ID gc_id. *== clearance CLEAR gt_test1. CLEAR gt_test2. CLEAR gv_xml. *== import data into xml string IMPORT test TO gv_xml FROM DATABASE indx(zv) ID gc_id. TRY . *== transform xml data into table with NEW structure CALL TRANSFORMATION id SOURCE XML gv_xml RESULT test = gt_test2. CATCH cx_transformation_error INTO gx_error. BREAK-POINT. ENDTRY.
- Interview mit Björn Schulz (Software-Heroes.com) - 3. September 2024
- Daten aus ALV ermitteln - 3. September 2024
- So lange es den SAPGUI noch gibt… - 27. Juni 2024